﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil.Cil;
using Mono.Cecil;
using System.Diagnostics;
using devtm.Aop.Extensions;

namespace devtm.Aop.Emit
{

    
    public class CilWorker : IDisposable
    {

       
        private ILProcessor gen;
        private List<Label> labels = new List<Label>();
        private MethodBody methodBody;
        internal Instruction cursor = null;
        private TryBlockCilWorker Try = null;


        public CilWorker(MethodBody methodBody)
        {
            this.methodBody = methodBody;            
            this.gen = methodBody.GetILProcessor();
            if (Body.Instructions.Count > 0)
                this.cursor = First;
        }


        public CilWorker(CilWorker parent)
        {
            // TODO: Complete member initialization
            this.methodBody = parent.methodBody;
            this.Parent = parent;
            this.gen = parent.gen;
        }


        public MethodBody Body { get { return gen.Body; } }
        public Instruction First { get { return Body.Instructions[0]; } }
        public Instruction Current { get { return cursor; } }
        public Instruction Last { get { return Body.Instructions[Body.Instructions.Count - 1]; } }
        internal CilWorker Parent { get; set; }

        public Instruction Start { get; set; }
        public Instruction End { get; set; }

        public string Name { get { return Body.Method.Name; } }
        public Mono.Collections.Generic.Collection<Instruction> Instructions { get { return Body.Instructions; } }


        #region Emit


        #region Move
        
        [DebuggerStepThrough]
        public void Locate(Instruction target) { cursor = target; }
        [DebuggerStepThrough]
        public Instruction LocateFirst() { return (cursor = Body.Instructions[0]); }
        [DebuggerStepThrough]
        public Instruction LocateLast() { return (cursor = Body.Instructions[Body.Instructions.Count - 1]); }
        [DebuggerStepThrough]
        public Instruction LocatePrevious() { return (cursor = cursor.Previous); }
        [DebuggerStepThrough]
        public Instruction LocateNext() { return (cursor = cursor.Next); }

        #endregion

        [DebuggerStepThrough]
        public Instruction Append(Instruction instruction)
        {
            gen.Append(instruction);
            return instruction;
        }

        #region Create
        
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode) { return gen.Create(opcode); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, byte value) { return gen.Create(opcode, value); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, CallSite site) { return gen.Create(opcode, site); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, double value) { return gen.Create(opcode, value); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, FieldReference field) { return gen.Create(opcode, field); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, float value) { return gen.Create(opcode, value); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, Instruction target) { return gen.Create(opcode, target); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, Instruction[] targets) { return gen.Create(opcode, targets); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, int value) { return gen.Create(opcode, value); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, long value) { return gen.Create(opcode, value); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, MethodReference method) { return gen.Create(opcode, gen.Body.Method.Module.Import(method)); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, ParameterDefinition parameter) { return gen.Create(opcode, parameter); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, sbyte value) { return gen.Create(opcode, value); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, string value) { return gen.Create(opcode, value); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, TypeReference type) { return gen.Create(opcode, gen.Body.Method.Module.Import(type)); }
        [DebuggerStepThrough]
        public Instruction Create(OpCode opcode, VariableDefinition variable) { return gen.Create(opcode, variable); }

        #endregion

        #region Emit

        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode) { return cursor = this.Append(this.Create(opcode)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, byte value) { return cursor = this.Append(this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, CallSite site) { return cursor = this.Append(this.Create(opcode, site)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, double value) { return cursor = this.Append(this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, FieldReference field) { return cursor = this.Append(this.Create(opcode, field)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, float value) { return cursor = this.Append(this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, Instruction target) { return cursor = this.Append(this.Create(opcode, target)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, Instruction[] targets) { return cursor = this.Append(this.Create(opcode, targets)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, int value) { return cursor = this.Append(this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, long value) { return cursor = this.Append(this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, MethodReference method) { return cursor = this.Append(this.Create(opcode, gen.Body.Method.Module.Import(method))); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, ParameterDefinition parameter) { return cursor = this.Append(this.Create(opcode, parameter)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, sbyte value) { return cursor = this.Append(this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, string value) { return cursor = this.Append(this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, TypeReference type) { return cursor = this.Append(this.Create(opcode, gen.Body.Method.Module.Import(type))); }
        [DebuggerStepThrough]
        public Instruction Emit(OpCode opcode, VariableDefinition variable) { return cursor = this.Append(this.Create(opcode, variable)); }

        #endregion

        #region Insert
       
        [DebuggerStepThrough]
        public Instruction Insert(Instruction instruction) { return cursor = this.InsertAfter(cursor, instruction); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode) { return cursor = this.InsertAfter(cursor, this.Create(opcode)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, byte value) { return cursor = this.InsertAfter(cursor, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, CallSite site) { return cursor = this.InsertAfter(cursor, this.Create(opcode, site)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, double value) { return cursor = this.InsertAfter(cursor, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, FieldReference field) { return cursor = this.InsertAfter(cursor, this.Create(opcode, field)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, float value) { return cursor = this.InsertAfter(cursor, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, Instruction target2) { return cursor = this.InsertAfter(cursor, this.Create(opcode, target2)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, Instruction[] targets) { return cursor = this.InsertAfter(cursor, this.Create(opcode, targets)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, int value) { return cursor = this.InsertAfter(cursor, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, long value) { return cursor = this.InsertAfter(cursor, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, MethodReference method) { return cursor = this.InsertAfter(cursor, this.Create(opcode, gen.Body.Method.Module.Import(method))); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, ParameterDefinition parameter) { return cursor = this.InsertAfter(cursor, this.Create(opcode, parameter)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, sbyte value) { return cursor = this.InsertAfter(cursor, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, string value) { return cursor = this.InsertAfter(cursor, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, TypeReference type) { return cursor = this.InsertAfter(cursor, this.Create(opcode, gen.Body.Method.Module.Import(type))); }
        [DebuggerStepThrough]
        public Instruction Insert(OpCode opcode, VariableDefinition variable) { return cursor = this.InsertAfter(cursor, this.Create(opcode, variable)); }
        [DebuggerStepThrough]
        public Instruction Insert(IEnumerable<Instruction> instructions) { return Insert(instructions.ToArray()); }
        
        [DebuggerStepThrough]
        public Instruction Insert(params Instruction[] instructions) 
        {

            foreach (var item in instructions)            
                cursor = this.InsertAfter(cursor, item);
            
            return cursor;

        }

        #endregion

        #region InsertAfter
        
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode) { return cursor = this.InsertAfter(target, this.Create(opcode)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, byte value) { return cursor = this.InsertAfter(target, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, CallSite site) { return cursor = this.InsertAfter(target, this.Create(opcode, site)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, double value) { return cursor = this.InsertAfter(target, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, FieldReference field) { return cursor = this.InsertAfter(target, this.Create(opcode, field)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, float value) { return cursor = this.InsertAfter(target, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, Instruction target2) { return cursor = this.InsertAfter(target, this.Create(opcode, target2)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, Instruction[] targets) { return cursor = this.InsertAfter(target, this.Create(opcode, targets)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, int value) { return cursor = this.InsertAfter(target, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, long value) { return cursor = this.InsertAfter(target, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, MethodReference method) { return cursor = this.InsertAfter(target, this.Create(opcode, gen.Body.Method.Module.Import(method))); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, ParameterDefinition parameter) { return cursor = this.InsertAfter(target, this.Create(opcode, parameter)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, sbyte value) { return cursor = this.InsertAfter(target, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, string value) { return cursor = this.InsertAfter(target, this.Create(opcode, value)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, TypeReference type) { return cursor = this.InsertAfter(target, this.Create(opcode, gen.Body.Method.Module.Import(type))); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, OpCode opcode, VariableDefinition variable) { return cursor = this.InsertAfter(target, this.Create(opcode, variable)); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, IEnumerable<Instruction> instructions) { return InsertAfter(target, instructions.ToArray()); }
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, Instruction instruction)
        {

            if (cursor != null)            
                gen.InsertAfter(target, instruction);                            
            else            
                gen.Append(instruction);

            return cursor = instruction;

        }        
        [DebuggerStepThrough]
        public Instruction InsertAfter(Instruction target, params Instruction[] instructions)
        {
            Locate(target);
            foreach (var item in instructions)
                cursor = this.InsertAfter(cursor, item);

            return cursor;

        }

        #endregion

        #region InsertBefore

        [DebuggerStepThrough]
        public Instruction InsertBefore(Instruction target, IEnumerable<Instruction> instructions) { return InsertBefore(target, instructions.ToArray()); }
        [DebuggerStepThrough]
        public Instruction InsertBefore(Instruction target, params Instruction[] instructions)
        {
            Locate(target);
            bool t = false;
            foreach (var item in instructions)
            {
                if (!t)
                {
                    cursor = this.InsertBefore(cursor, item);
                    t = true;
                }
                else
                {
                    cursor = this.InsertAfter(cursor, item);
                }                
            }

            return cursor;

        }
        [DebuggerStepThrough]
        public Instruction InsertBefore(Instruction target, Instruction instruction)
        {
            gen.InsertBefore(target, instruction);
            return cursor = instruction;
        }
        [DebuggerStepThrough]
        public Instruction InsertBefore(Instruction target, OpCode opCode)
        {
            Instruction instruction = Create(opCode);
            gen.InsertBefore(target, instruction);
            return cursor = instruction;
        }

        #endregion


        [DebuggerStepThrough]
        public Instruction Remove(Instruction instruction)
        {
            gen.Remove(instruction);
            return instruction;
        }


        [DebuggerStepThrough]
        public Instruction Replace(Instruction target, Instruction instruction)
        {
            gen.Replace(target, instruction);
            return instruction;
        }

        #endregion


        #region Labels

        [DebuggerStepThrough]
        public Label DefineLabel()
        {
            Label label = new Label(labels.Count);
            labels.Add(label);
            return label;
        }

        [DebuggerStepThrough]
        public Instruction Emit(OpCode opCode, Label label)
        {
            bool empty = label.Instruction == null;
            Instruction i = label.Instruction ?? this.Body.Instructions[0];
            Instruction ret = Emit(opCode, i);
            if (empty)
                label.Instructions.Add(ret);
            return ret;
        }

        [DebuggerStepThrough]
        public Instruction Insert(OpCode opCode, Label label)
        {
            bool empty = label.Instruction == null;
            Instruction i = label.Instruction ?? this.Body.Instructions[0];
            Instruction ret = Insert(opCode, i);
            if (empty)
                label.Instructions.Add(ret);
            return ret;
        }

        //[DebuggerStepThrough]
        public Instruction MarkLabel(Label label, Func<CilWorker, Instruction> f)
        {

            if (label.Instruction != null)
                throw new Exception("Label already marked");

            label.Instruction = f(this);

            foreach (Instruction i in label.Instructions)
                i.Operand = label.Instruction;

            label.Instructions.Clear();

            cursor = label.Instruction;

            return label.Instruction;

        }


        public Instruction MarkLabel(Label label)
        {

            if (label.Instruction != null)
                throw new Exception("Label already marked");

            foreach (Instruction i in label.Instructions)
                i.Operand = cursor;

            label.Instructions.Clear();

            return label.Instruction;

        }

        #endregion


        #region Variables

        [DebuggerStepThrough]
        public VariableDefinition Declare(TypeReference type)
        {
            VariableDefinition v = new VariableDefinition(type);
            methodBody.Variables.Add(v);
            return v;
        }

        [DebuggerStepThrough]
        public VariableDefinition Declare(Type type)
        {
            VariableDefinition v = new VariableDefinition(Body.Method.Module.Import(type));
            methodBody.Variables.Add(v);
            return v;
        }

        [DebuggerStepThrough]
        public VariableDefinition Declare(TypeReference type, string name)
        {
            VariableDefinition v = new VariableDefinition(name, type);
            methodBody.Variables.Add(v);
            return v;
        }

        #endregion


        #region IDisposable

        ~CilWorker()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
        }

        public void Dispose(bool disposing)
        {

            if (disposing)
            {
                methodBody.InitLocals = true;
            }

        }

        #endregion


        [DebuggerStepThrough]
        public bool CurrentIs(params Code[] codes)
        {
            bool ret = cursor.Is(codes);
            return ret;
        }

        public CilWorker CreateCursor()
        {
            CilWorker cur = new CilWorker(this);
            return cur;
        }

        public TryFinallyCilWorker CreateTryFinallyBloc()
        {

            TryFinallyCilWorker cur = new TryFinallyCilWorker(this);

            return cur;

        }

        public TryBlockCilWorker TryBegin(Instruction firstTryInstruction, Instruction lastTryInstruction)
        {
            Try = new TryBlockCilWorker(this, firstTryInstruction, lastTryInstruction);
            Try.Parent = this;
            return Try;
        }


        #region Find

        /// <summary>
        /// Parse all instructions from current to last if firstToEnd is true or to first if firstToEnd is false
        /// </summary>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public Instruction Find(bool firstToEnd, Code code)
        {
            Instruction instructionEnd = firstToEnd ? Last : First;
            return Find(Current, instructionEnd, firstToEnd, code);
        }


        /// <summary>
        /// Parse all instructions from Current position to instructionEnd
        /// Finds the specified instruction code.
        /// </summary>
        /// <param name="instructionEnd">The instruction end.</param>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public Instruction Find(Instruction instructionEnd, bool firstToEnd, Code code)
        {
            return Find(Current, instructionEnd, firstToEnd, code);
        }


        /// <summary>
        /// Parse all instructions from instructionStart to instructionEnd
        /// Finds the specified instruction code.
        /// </summary>
        /// <param name="instructionStart">The instruction start.</param>
        /// <param name="instructionEnd">The instruction end.</param>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public Instruction Find(Instruction instructionStart, Instruction instructionEnd, bool firstToEnd, Code code)
        {

            Instruction instruction = instructionStart;

            while (instruction.OpCode.Code != code || instruction == instructionEnd)
            {

                if (firstToEnd)
                {
                    if (instruction == Last)
                        return null;
                    instruction = instruction.Next;
                }
                else
                {
                    if (instruction == First)
                        return null;
                    instruction = instruction.Previous;                    
                }

            }

            return instruction;

        }

        #endregion


        #region GetBlock


        /// <summary>
        /// return all instructions from current to last if firstToEnd is true or to first if firstToEnd is false
        /// </summary>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public IEnumerable<Instruction> GetBlock(bool firstToEnd, Code code)
        {
            Instruction instructionEnd = firstToEnd ? Last : First;
            return GetBlock(Current, instructionEnd, firstToEnd, code);
        }


        /// <summary>
        /// return all instructions from Current position to instructionEnd
        /// </summary>
        /// <param name="instructionEnd">The instruction end.</param>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public IEnumerable<Instruction> GetBlock(Instruction instructionEnd, bool firstToEnd, Code code)
        {
            return GetBlock(Current, instructionEnd, firstToEnd, code);
        }


        /// <summary>
        /// return all instructions from instructionStart to instructionEnd
        /// </summary>
        /// <param name="instructionStart">The instruction start.</param>
        /// <param name="instructionEnd">The instruction end.</param>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public IEnumerable<Instruction> GetBlock(Instruction instructionStart, Instruction instructionEnd, bool firstToEnd, Code code)
        {

            Instruction instruction = instructionStart;

            while (instruction.OpCode.Code != code || instruction != instructionEnd)
            {
                yield return instruction;

                if (firstToEnd)
                {

                    if (instruction == Last)                    
                        yield break;
                    
                    instruction = instruction.Next;
                }
                else
                {

                    if (instruction == First)
                        yield break;

                    instruction = instruction.Previous;
                }

            }


        }


        /// <summary>
        /// return all instructions from current to last if firstToEnd is true or to first if firstToEnd is false
        /// </summary>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <returns></returns>
        public IEnumerable<Instruction> GetBlock(bool firstToEnd)
        {
            Instruction instructionEnd = firstToEnd ? Last : First;
            return GetBlock(Current, instructionEnd, firstToEnd);
        }


        /// <summary>
        /// return all instructions from Current position to instructionEnd
        /// </summary>
        /// <param name="instructionEnd">The instruction end.</param>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <returns></returns>
        public IEnumerable<Instruction> GetBlock(Instruction instructionEnd, bool firstToEnd)
        {
            return GetBlock(Current, instructionEnd, firstToEnd);
        }


        /// <summary>
        /// return all instructions from instructionStart to instructionEnd
        /// </summary>
        /// <param name="instructionStart">The instruction start.</param>
        /// <param name="instructionEnd">The instruction end.</param>
        /// <param name="firstToEnd">if set to <c>true</c> [first to end].</param>
        /// <returns></returns>
        public IEnumerable<Instruction> GetBlock(Instruction instructionStart, Instruction instructionEnd, bool firstToEnd)
        {

            Instruction instruction = instructionStart;

            while (instruction != instructionEnd)
            {
                yield return instruction;

                if (firstToEnd)
                {

                    if (instruction == Last)
                        yield break;

                    instruction = instruction.Next;
                }
                else
                {

                    if (instruction == First)
                        yield break;

                    instruction = instruction.Previous;
                }

            }

            yield return instruction;

        }


        public List<Instruction> Cut(Instruction instructionStart, Instruction instructionEnd)
        {

            var lst = GetBlock(instructionStart, instructionEnd, true).ToList();

            foreach (Instruction i in lst)
                Remove(i);

            return lst;

        }

        
        public List<Instruction> MoveEnd(Instruction instructionStart, Instruction instructionEnd)
        {
            return Move(instructionStart, instructionEnd, Last);
        }

        public List<Instruction> MoveStart(Instruction instructionStart, Instruction instructionEnd)
        {
            return Move(instructionStart, instructionEnd, First);
        }

        public List<Instruction> Move(Instruction instructionStart, Instruction instructionEnd, Instruction targetLocation)
        {

            var lst = GetBlock(instructionStart, instructionEnd, true).ToList();

            foreach (Instruction i in lst)
                Remove(i);

            Locate(targetLocation);

            foreach (Instruction item in lst)
                Insert(item);

            return lst;

        }
        
        #endregion

        public void Clear()
        {
            cursor = null;
            Body.Instructions.Clear();            
        }
        
    
    }



}
